package com.hzqy.web.ac.pms;

import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.*;

import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import com.hzqy.commons.utils.ConstantUtils;
import com.hzqy.commons.utils.HttpGetData;
import com.hzqy.commons.utils.SessionKey;
import com.hzqy.commons.utils.SystemConfigUtils;
import com.hzqy.web.vo.PmsUserVo;
import com.hzqy.web.vo.pms.PmsLoginAspectVo;

@Aspect
@Order(1)
@Component
public class PmsAspect {
	protected final Logger LOG=LoggerFactory.getLogger(getClass());

    @Pointcut("execution(public * com.hzqy.web.ac.pms.PmsAction.login(..))||execution(public * com.hzqy.web.ac.pms.PmsAction.sendMessage(..))")
    public void declearJoinPointExpression(){}

    
    @Before("declearJoinPointExpression()") //该标签声明次方法是一个前置通知：在目标方法开始之前执行
    public void beforMethod(JoinPoint joinPoint){}

    @After("declearJoinPointExpression()")
    public void afterMethod(JoinPoint joinPoint){}
    
    @AfterReturning(value="declearJoinPointExpression()",returning="result")
    public void afterReturnMethod(JoinPoint joinPoint,Object result){}

    @AfterThrowing(value="declearJoinPointExpression()",throwing="ex")
    public void afterThrowingMethod(JoinPoint joinPoint,Exception ex){}
   
    /**
     * 登录先检测，1、IP是否已达到总次数。2、用户名连续登录失败次数是否已达到规定次数
     * @param joinPoint
     */
    @Around(value="declearJoinPointExpression()")
    public Object aroundMethod(ProceedingJoinPoint point){
    	Object result = null;
        String methodName = point.getSignature().getName();
        //获取初始登录失败值---开始
        String loginFailTimeStr = SystemConfigUtils.getSysConfig(SessionKey.SESSION_SYSTEM_CONFIG.system_login_fail_time.getKey());
        int loginFailTime = 5;
        if(loginFailTimeStr != null && !loginFailTimeStr.trim().equals(""))
        	loginFailTime = Integer.parseInt(loginFailTimeStr);
        String loginFailCountStr = SystemConfigUtils.getSysConfig(SessionKey.SESSION_SYSTEM_CONFIG.system_login_fail_count.getKey());
        int loginFailCount = 5;
        if(loginFailCountStr != null && !loginFailCountStr.trim().equals(""))
        	loginFailCount = Integer.parseInt(loginFailCountStr);
        String loginIpTimeStr = SystemConfigUtils.getSysConfig(SessionKey.SESSION_SYSTEM_CONFIG.system_login_ip_time.getKey());
        int loginIpTime = 5;
        if(loginIpTimeStr != null && !loginIpTimeStr.trim().equals(""))
        	loginIpTime = Integer.parseInt(loginIpTimeStr);
        String loginIpCountStr = SystemConfigUtils.getSysConfig(SessionKey.SESSION_SYSTEM_CONFIG.system_login_ip_count.getKey());
        int loginIpCount = 5;
        if(loginIpCountStr != null && !loginIpCountStr.trim().equals(""))
        	loginIpCount = Integer.parseInt(loginIpCountStr);
        //String loginAdminIpStr = SystemConfigUtils.getSysConfig(SessionKey.SESSION_SYSTEM_CONFIG.system_login_admin_ip.getKey());

		String loginFailLockTimeStr = SystemConfigUtils.getSysConfig("system_login_fail_lock_time");
		int loginFailLockTime = 10;
		if(loginFailLockTimeStr != null && !loginFailLockTimeStr.trim().equals(""))
			loginFailLockTime = Integer.parseInt(loginFailLockTimeStr);
		String loginFailLockCountStr = SystemConfigUtils.getSysConfig("system_login_fail_lock_count");
		int loginFailLockCount = 10;
		if(loginFailLockCountStr != null && !loginFailLockCountStr.trim().equals(""))
			loginFailLockCount = Integer.parseInt(loginFailLockCountStr);

        //获取初始登录失败值---结束
        List<Object> requestParams = Arrays.asList(point.getArgs());
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
    	HttpSession session = request.getSession();
    	ServletContext application = session.getServletContext();
    	String title = session.getServletContext().getInitParameter("title");
    	
        try {
            //前置通知
        	//LOG.debug("The method "+ methodName+" start. param<"+ Arrays.asList(point.getArgs())+">");
        	Object userNameObj = requestParams.get(1); //取到登录用户名
        	String userName = "";
        	if(userNameObj != null) //这里有可能用户只是打开登录页面
        		userName = (String)userNameObj;
        	//LOG.debug("userNameObj="+userNameObj+"==userName="+userName);
        	String user_ip=HttpGetData.getIpAddr(request);
        	
        	//开始判断超管的登录IP限制
        	/*if(userName!=null && userName.trim().equalsIgnoreCase("admin") && loginAdminIpStr!=null
        			&& loginAdminIpStr.trim().length()>3 && user_ip!=null 
        			&& loginAdminIpStr.indexOf(user_ip)==-1) {
        		Map<String,String> resultMap = new HashMap<String,String>();
        		resultMap.put("title", title);
        		resultMap.put("msg", "超管账号登录IP受限，请确认是否在可登录IP清单中。");
        		LOG.error("超管账号登录IP受限，请确认是否在可登录IP清单中。可登录IP清单为："+loginAdminIpStr+"，登录IP为："+user_ip);
        		return resultMap;
        	}*/
        	//结束判断超管的登录IP限制
        	
        	HashMap<String,ArrayList<PmsLoginAspectVo>> applicationLoginIpHashMap = null;
        	HashMap<String,ArrayList<PmsLoginAspectVo>> applicationLoginFailHashMap = null;
        	HashMap<String,ArrayList<PmsLoginAspectVo>> applicationLoginFailLockHashMap = null;
        	Object applicationLoginIpObject = application.getAttribute("applicationLoginIpHashMap");
        	if(applicationLoginIpObject==null) 
        		applicationLoginIpHashMap = new HashMap<String,ArrayList<PmsLoginAspectVo>>();
        	else {
        		applicationLoginIpHashMap = (HashMap<String,ArrayList<PmsLoginAspectVo>>)applicationLoginIpObject;
        	}
        	Object applicationLoginFailObject = application.getAttribute("applicationLoginFailHashMap");
        	if(applicationLoginFailObject==null) 
        		applicationLoginFailHashMap = new HashMap<String,ArrayList<PmsLoginAspectVo>>();
        	else {
        		applicationLoginFailHashMap = (HashMap<String,ArrayList<PmsLoginAspectVo>>)applicationLoginFailObject;
        	}

			Object applicationLoginFailLockObject = application.getAttribute("applicationLoginFailLockHashMap");
			if(applicationLoginFailLockObject==null)
				applicationLoginFailLockHashMap = new HashMap<String,ArrayList<PmsLoginAspectVo>>();
			else {
				applicationLoginFailLockHashMap = (HashMap<String,ArrayList<PmsLoginAspectVo>>)applicationLoginFailLockObject;
			}

        	ArrayList<PmsLoginAspectVo> loginIpCountList = applicationLoginIpHashMap.get(user_ip); //查询得到此IP的登录次数
        	if(loginIpCountList == null) 
        		loginIpCountList = new ArrayList<PmsLoginAspectVo>();
        	
        	//开始删除超时的登录IP
        	ArrayList<PmsLoginAspectVo> tempRemoveIPList = new ArrayList<PmsLoginAspectVo>();
        	for(int i = 0; i < loginIpCountList.size(); i++) {
        		//LOG.debug("时间="+(System.currentTimeMillis()-loginIpCountList.get(i).getF_pla_login_fail_time())+"=time="+loginIpTime*60*1000);
        		if((System.currentTimeMillis()-loginIpCountList.get(i).getF_pla_login_ip_time())>loginIpTime*60*1000) {
        			tempRemoveIPList.add(loginIpCountList.get(i));
        		}
        	}
        	loginIpCountList.removeAll(tempRemoveIPList);
        	//结束删除超时的登录IP
        	
        	LOG.debug("loginIpCountList.size()="+loginIpCountList.size()+"==loginIpCount="+loginIpCount);
        	if(loginIpCountList.size()>=loginIpCount-1) {
        		Map<String,String> resultMap = new HashMap<String,String>();
        		resultMap.put("title", title);
        		resultMap.put("msg", "IP登录受限，已达到最大登录数。");
        		return resultMap;
        	}
        	
        	ArrayList<PmsLoginAspectVo> loginFailCountList = applicationLoginFailHashMap.get(userName);
        	if(loginFailCountList == null) 
        		loginFailCountList = new ArrayList<PmsLoginAspectVo>();
        	//开始删除超时的登录用户名
        	ArrayList<PmsLoginAspectVo> tempRemoveFailList = new ArrayList<PmsLoginAspectVo>();
        	for(int i = 0; i < loginFailCountList.size(); i++) {
        		//LOG.debug("时间="+(System.currentTimeMillis()-loginFailCountList.get(i).getF_pla_login_fail_time())+"=loginFailTime="+loginFailTime*60*1000);
        		if((System.currentTimeMillis()-loginFailCountList.get(i).getF_pla_login_fail_time())>loginFailTime*60*1000) {
        			tempRemoveFailList.add(loginFailCountList.get(i));
        		}
        	}
        	loginFailCountList.removeAll(tempRemoveFailList);
        	//结束删除超时的登录用户名
        	
        	LOG.debug("loginFailCountList.size()="+loginFailCountList.size()+"==loginFailCount="+loginFailCount);
        	if(loginFailCountList.size()>=loginFailCount) {
        		Map<String,String> resultMap = new HashMap<String,String>();
        		resultMap.put("title", title);
        		resultMap.put("msg", "用户连续登录失败次数已达到限制。请稍后尝试。");
        		return resultMap;
        	}

			ArrayList<PmsLoginAspectVo> loginFailLockCountList = applicationLoginFailLockHashMap.get(userName);
			if(loginFailLockCountList == null)
				loginFailLockCountList = new ArrayList<PmsLoginAspectVo>();
			//开始删除超时的登录用户名
			ArrayList<PmsLoginAspectVo> tempRemoveLockFailList = new ArrayList<PmsLoginAspectVo>();
			for(int i = 0; i < loginFailLockCountList.size(); i++) {
				//LOG.debug("时间="+(System.currentTimeMillis()-loginFailCountList.get(i).getF_pla_login_fail_time())+"=loginFailTime="+loginFailTime*60*1000);
				if((System.currentTimeMillis()-loginFailLockCountList.get(i).getF_pla_login_fail_lock_time())>loginFailLockTime*60*1000) {
					tempRemoveLockFailList.add(loginFailLockCountList.get(i));
				}
			}
			loginFailLockCountList.removeAll(tempRemoveLockFailList);
			//结束删除超时的登录用户名

			LOG.debug("loginFailLockCountList.size()="+loginFailLockCountList.size()+"==loginFailLockCount="+loginFailLockCount);
			if(loginFailLockCountList.size()>=loginFailLockCount) {
				Map<String,String> resultMap = new HashMap<String,String>();
				resultMap.put("title", title);
				resultMap.put("msg", "用户连续登录失败次数已达到锁定上限,已冻结。");
				return resultMap;
			}
        	
            //执行目标方法
            result = point.proceed();
            
            
            //返回通知
            //LOG.debug("The method "+ methodName+" end. result<"+ result+">");
            String status = "";
            if(result instanceof String) {
            	status = "success";
            } else {
            	Map<String,String> resultMap = ((Map<String,String>)result);
            	status = resultMap.get("status");
            }
            
            if(status!=null && !status.equals("login")) { //返回状态不为空，并且状态不是只显示登录页面
            	PmsLoginAspectVo plav = new PmsLoginAspectVo();
        		plav.setF_pla_name(userName);
        		plav.setF_pla_ip(user_ip);
        		plav.setF_pla_login_ip_time(System.currentTimeMillis());
        		plav.setF_pla_login_fail_time(System.currentTimeMillis());
        		plav.setF_pla_login_fail_lock_time(System.currentTimeMillis());
            	if(status.equals("success")) { //登录成功
            		loginIpCountList.add(plav);
            		applicationLoginIpHashMap.put(user_ip, loginIpCountList);
            		application.setAttribute("applicationLoginIpHashMap", applicationLoginIpHashMap);
            		applicationLoginFailHashMap.put(userName, null); //当用户登录成功后，将前面登录失败的次数清零。
					applicationLoginFailLockHashMap.put(userName, null);
            		
            		//登录成功后，如果在别的地方登录过了，则先将原先的session变成invalidate，然后将最后一次登录的session存入application
            		Object applicationLoginSessionObj = application.getAttribute("applicationLoginSession_"+userName);
            		HttpSession applicationLoginSession = null;
            		if(applicationLoginSessionObj!=null)
            			applicationLoginSession = (HttpSession)applicationLoginSessionObj;
            		if(applicationLoginSession==null)
            			application.setAttribute("applicationLoginSession_"+userName, session);
            		else {
            			//LOG.debug("dpf===applicationLoginSession_="+applicationLoginSession+"===session=="+session);
            			try {
            				if(!applicationLoginSession.equals(session))
            					applicationLoginSession.invalidate();
            			} catch (Exception e) {
            				
            			}
            			application.removeAttribute("applicationLoginSession_"+userName);
            			application.setAttribute("applicationLoginSession_"+userName, session);
            		}
            	} else { //登录失败
            		loginFailCountList.add(plav);
            		applicationLoginFailHashMap.put(userName, loginFailCountList);
            		application.setAttribute("applicationLoginFailHashMap", applicationLoginFailHashMap);
					loginFailLockCountList.add(plav);
					applicationLoginFailLockHashMap.put(userName, loginFailLockCountList);
					application.setAttribute("applicationLoginFailLockHashMap", applicationLoginFailLockHashMap);
            	}
            }
            
        } catch (Throwable e) {
            //异常通知
        	//LOG.debug("this method "+methodName+" end.ex message<"+e+">");
            throw new RuntimeException(e);
        }
        //后置通知
//        LOG.debug("The method "+ methodName+" end.");
        return result;
    }
}
